#ifndef __BONUSFACTORY_H__
#define __BONUSFACTORY_H__

#include <iostream>
#include <ctime>
#include "Bonus.h"
#include "ComidaBonus.h"
#include "MultiplicaPuntosBonus.h"
#include "DuplicarVelocidadBonus.h"
#include "FantasmasAOponenteBonus.h"
#include "CongelarOponenteBonus.h"
#include "ReducirVelocidadBonus.h"
#include "PerseguirFantasmasBonus.h"
#include "SumarPuntosDelOponenteBonus.h"
#include "TipoBonus.h"
#include "Lista.h"


class BonusFactory {


private:

	// cantidades actuales
	int cantidadMultiplicador, cantidadDuplicarVel, cantidadReducirVel, cantidadCongelar;
	int cantidadPerseguirFantasmas, cantidadFantasmasAOponente, cantidadSumarPuntosOp;

	// cantidades maximas
	int maxMultiplicador, maxDuplicarVel, maxReducirVel, maxCongelar;
	int maxPerseguirFantasmas, maxFantasmasAOponente, maxSumarPuntosOp;

	/* 
	 * Matriz con las probabilidades de cada tipo de Bonus
	 * int[0] = probabilidad multiplicador
	 * int[1] = probabilidad duplicar velocidad 
	 * int[2] = probabilidad reducir velocidad
	 * int[3] = probabilidad congelar oponente
	 * int[4] = probabilidad perseguir fantasmas
	 * int[5] = probabilidad fantasmas a oponente
	 * int[6] = probabilidad sumar ptos. oponente
	 */
	int* probabilidades;

	/*
	 * Metodo que devuelve el rango minimo dependiendo de la probabilidad del tipo de bonus en la posicion pasada
	 * por parametro
	 */
	int getMinRangoProbabilidad(int posicion){
		
		int rangoMin = 0;

		for (int i = 0; i < posicion; i++){
			rangoMin += this->probabilidades[i];
		}

		return rangoMin+1;
	}

	/*
	 * Metodo que devuelve el rango maximo dependiendo de la probabilidad del tipo de bonus en la posicion pasada
	 * por parametro
	 */
	int getMaxRangoProbabilidad(int posicion){
		
		int rangoMax = 0;

		for (int i = 0; i <= posicion; i++){
			rangoMax += this->probabilidades[i];
		}

		return rangoMax;
	}

	/*
	 * Metodo que, recorriendo la lista de tipos de bonus, inicializa las cantidades maximas de creaciones
	 * de cada tipo asi como tambien la probabilidad de aparicion de cada uno.
	 */
	void inicializarValores(Lista<TipoBonus*>* tiposBonus){

		IteradorLista<TipoBonus*> it = tiposBonus->iterador();
		while(it.tieneSiguiente()){
			TipoBonus* tipoBonus = it.siguiente();
			string tipo = tipoBonus->getNombre();
			int cantidadMaxima = tipoBonus->getCantidadMaxima();
			int probabilidad = tipoBonus->getProbabilidadDeAparicion();

			if(tipo == "multiplicadorPuntos"){
				this->maxMultiplicador = cantidadMaxima;
				this->probabilidades[0] = probabilidad;
			} else if(tipo == "duplicarVelocidad"){
				this->maxDuplicarVel = cantidadMaxima;
				this->probabilidades[1] = probabilidad;
			} else if(tipo == "reducirVelocidad"){
				this->maxReducirVel = cantidadMaxima;
				this->probabilidades[2] = probabilidad;
			} else if(tipo == "congelarOponente"){
				this->maxCongelar = cantidadMaxima;
				this->probabilidades[3] = probabilidad;
			} else if(tipo == "perseguirAFantasmas"){
				this->maxPerseguirFantasmas = cantidadMaxima;
				this->probabilidades[4] = probabilidad;
			} else if(tipo == "fantasmasAOponente"){
				this->maxFantasmasAOponente = cantidadMaxima;
				this->probabilidades[5] = probabilidad;
			} else if(tipo == "sumarPuntosDelOponente"){
				this->maxSumarPuntosOp = cantidadMaxima;
				this->probabilidades[6] = probabilidad;
			}
		}
	}


public: 

	// Constructor
	BonusFactory(Lista<TipoBonus*>* tiposBonus){
		this->cantidadMultiplicador = 0;
		this->cantidadDuplicarVel = 0;
		this->cantidadReducirVel = 0;
		this->cantidadCongelar = 0;
		this->cantidadPerseguirFantasmas = 0;
		this->cantidadFantasmasAOponente = 0; 
		this->cantidadSumarPuntosOp = 0;

		this->probabilidades = new int[7];

		inicializarValores(tiposBonus);

	}


	// Metodo que genera un Bonus de cierto tipo segun su probabilidad y cantidad maxima de apariciones 
	Bonus* generarBonus(){

		Bonus* bonus = NULL;
		int eleccion = 0; 

		/*
		 * Se genera un numero aleatorio para elegir el tipo de bonus en base a su probabilidad de
		 * generacion
		 */
		srand((unsigned)time(0));
		int menor=1;
		int mayor=100;
		int rango=(mayor-menor)+1;
		eleccion = rand()%(mayor-menor)+menor;

		/*
		 * Si el Bonus que se generara ya llego a su cantidad maxima, no se genera otro en ese momento
		 */

		if ((eleccion > getMinRangoProbabilidad(0)) && (eleccion <= getMaxRangoProbabilidad(0))) {
			if(this->cantidadMultiplicador < this->maxMultiplicador){
				cout << "MultiplicaPuntosBonus creado" << endl << endl;
				bonus = new MultiplicaPuntosBonus();
				this->cantidadMultiplicador++;
			}

		} else if ((eleccion > getMinRangoProbabilidad(1)) && (eleccion <= getMaxRangoProbabilidad(1))) {
			if(this->cantidadDuplicarVel < this->maxDuplicarVel){
				cout << "DuplicarVelocidadBonus creado" << endl << endl;
				bonus = new DuplicarVelocidadBonus();
				this->cantidadDuplicarVel++;
			}

		} else if ((eleccion > getMinRangoProbabilidad(2)) && (eleccion <= getMaxRangoProbabilidad(2))) {
			if(this->cantidadReducirVel < this->maxReducirVel){
				cout << "ReducirVelocidadBonus creado" << endl << endl;
				bonus = new ReducirVelocidadBonus();
				this->cantidadReducirVel++;
			}

		} else if ((eleccion > getMinRangoProbabilidad(3)) && (eleccion <= getMaxRangoProbabilidad(3))) {
			if(this->cantidadCongelar < this->maxCongelar){
				cout << "CongelarOponenteBonus creado" << endl << endl;
				bonus = new CongelarOponenteBonus();
				this->cantidadCongelar++;
			}

		} else if ((eleccion > getMinRangoProbabilidad(4)) && (eleccion <= getMaxRangoProbabilidad(4))) {
			if(this->cantidadPerseguirFantasmas < this->maxPerseguirFantasmas){
				cout << "PerseguirFantasmasBonus creado" << endl << endl;
				bonus = new PerseguirFantasmasBonus();
				this->cantidadPerseguirFantasmas++;
			}
		} else if ((eleccion > getMinRangoProbabilidad(5)) && (eleccion <= getMaxRangoProbabilidad(5))) {
			if(this->cantidadFantasmasAOponente < this->maxFantasmasAOponente){
				cout << "FantasmasAOponenteBonus creado" << endl << endl;
				bonus = new FantasmasAOponenteBonus();
				this->cantidadFantasmasAOponente++;
			}
		} else if ((eleccion > getMinRangoProbabilidad(6)) && (eleccion <= getMaxRangoProbabilidad(6))) {
			if(this->cantidadSumarPuntosOp < this->maxSumarPuntosOp){
				cout << "SumarPuntosDelOponenteBonus creado" << endl << endl;
				bonus = new SumarPuntosDelOponenteBonus();
				this->cantidadSumarPuntosOp++;
			}
		}

		return bonus;
	}


	/* GETTERS Y SETTERS DE PROBABILIDADES DE CADA TIPO DE BONUS */
	
	void setProbabilidadMultiplicaPuntosBonus(int probabilidad){
		this->probabilidades[0] = probabilidad;	
	}

	int getProbabilidadMultiplicaPuntosBonus(){
		return this->probabilidades[0];
	}

	void setProbabilidadDuplicarVelocidadBonus(int probabilidad){
		this->probabilidades[1] = probabilidad;
	}

	int getProbabilidadDuplicarVelocidadBonus(){
		return this->probabilidades[1];
	}

	void setProbabilidadReducirVelocidadBonus(int probabilidad){
		this->probabilidades[2] = probabilidad;	
	}

	int getProbabilidadReducirVelocidadBonus(){
		return this->probabilidades[2];
	}

	void setProbabilidadCongelarOponenteBonus(int probabilidad){
		this->probabilidades[3] = probabilidad;	
	}

	int getProbabilidadCongelarOponenteBonus(){
		return this->probabilidades[3];
	}

	void setProbabilidadPerseguirFantasmasBonus(int probabilidad){
		this->probabilidades[4] = probabilidad;	
	}

	int getProbabilidadPerseguirFantasmasBonus(){
		return this->probabilidades[4];
	}

	void setProbabilidadFantasmasAOponenteBonus(int probabilidad){
		this->probabilidades[5] = probabilidad;	
	}

	int getProbabilidadFantasmasAOponenteBonus(){
		return this->probabilidades[5];
	}

	void setProbabilidadSumarPuntosDelOponenteBonus(int probabilidad){
		this->probabilidades[6] = probabilidad;	
	}

	int getProbabilidadSumarPuntosDelOponenteBonus(){
		return this->probabilidades[6];
	}


	/* GETTERS Y SETTERS DE CANTIDADES MAXIMAS DE CADA TIPO DE BONUS */

	int getMaxMultiplicador(){
		return this->maxMultiplicador;
	}
	
	void setMaxMultiplicador(int max){
		this->maxMultiplicador = max;
	}
	
	int getMaxDuplicarVel(){
		return this->maxDuplicarVel;
	}
	
	void setMaxDuplicarVel(int max){
		this->maxDuplicarVel = max;
	}
	
	int getMaxReducirVel(){
		return this->maxReducirVel;
	}
	
	void setMaxReducirVel(int max){
		this->maxReducirVel = max;
	}
	
	int getMaxCongelar(){
		return this->maxCongelar;
	}
	
	void setMaxCongelar(int max){
		this->maxCongelar = max;
	}

	int getMaxPerseguirFantasmas(){
		return this->maxPerseguirFantasmas;
	}
	
	void setMaxPerseguirFantasmas(int max){
		this->maxPerseguirFantasmas = max;
	}
	
	int getMaxFantasmasAOponente(){
		return this->maxFantasmasAOponente;
	}
	
	void setMaxFantasmasAOponente(int max){
		this->maxFantasmasAOponente = max;
	}
	
	int getMaxSumarPuntosOp(){
		return this->maxSumarPuntosOp;
	}
	
	void setMaxSumarPuntosOp(int max){
		this->maxSumarPuntosOp = max;
	}


	/* GETTERS DE CANTIDADES CREADAS DE CADA TIPO DE BONUS */

	int getCantidadMultiplicador(){
		this->cantidadMultiplicador;
	}
	
	int getCantidadDuplicarVel(){
		this->cantidadDuplicarVel;
	}
	
	int getCantidadReducirVel(){
		this->cantidadReducirVel;
	}
	
	int getCantidadCongelar(){
		this->cantidadCongelar;
	}
	
	int getCantidadPerseguirFantasmas(){
		this->cantidadPerseguirFantasmas;
	}
	
	int getCantidadFantasmasAOponente(){
		this->cantidadFantasmasAOponente;
	}
	
	int getCantidadSumarPuntosOp(){
		this->cantidadSumarPuntosOp;
	}


};

#endif